<?php
/**
 * [WeEngine System] Copyright (c) 2014 WE7.CC
 * WeEngine is NOT a free software, it under the license terms, visited http://www.we7.cc/ for more details.
 */
define('IN_IA', true);
define('IA_INIT_ROOT', str_replace("\\", '/', dirname(__FILE__)));

require IA_INIT_ROOT . '/data/config.php';
$db = array(
	'server' => $config['db']['master']['host'],
	'port' => $config['db']['master']['port'],
	'username' => $config['db']['master']['username'],
	'password' => $config['db']['master']['password'],
	'prefix' => $config['db']['master']['tablepre'],
	'name' => $config['db']['master']['database'],
);
$cookiepre = $config['cookie']['pre'];
$authkey = $config['setting']['authkey'];

$database_result = we7_build_db($db['server'], $db['username'], $db['password'], $db['name'], $db['prefix']);
if ($database_result !== true) {
	line('配置文件初始化失败！');
}

if (!file_exists(IA_INIT_ROOT . '/data/db.lock')) {
	$database_result = we7_db($db, $cookiepre, $authkey);
	if ($database_result !== true) {
		line($database_result);
	}
	touch(IA_INIT_ROOT . '/data/db.lock');
}

if (!file_exists(IA_INIT_ROOT . '/data/install.lock')) {
	require IA_INIT_ROOT . '/framework/bootstrap.inc.php';
	load()->model('cloud');
	sleep(10);
	$_W['siteroot'] = getenv('DOMAIN_URL');
	$result = cloud_reset_siteinfo();
	if ('success' != $result['data']) {
		line('站点初始化失败！');
	}
	touch(IA_INIT_ROOT . '/data/install.lock');
}

rename('install.php', 'install.php.bak');

line('success');


function line($string, $eol = true) {
	$string = $eol ? $string . PHP_EOL : $string;
	fwrite(STDOUT, $string . PHP_EOL);
	exit;
}


function we7_pdo($link, $method, $sql) {
	if (empty($link) || empty($method) || empty($sql)) {
		return false;
	}
	if (!($link instanceof PDO)) {
		trigger_error('$link不是有效的数据库连接：' . (string) $link);
		return false;
	}
	$statement = $link->$method($sql);
	if ($link->errorCode() != '00000') {
		$errorInfo = $link->errorInfo();
		trigger_error($errorInfo[0] . ": " . $errorInfo[2], E_USER_WARNING);
		return false;
	}
	if ($statement instanceof PDOStatement) {
		$result = $statement->fetch();
		if (!in_array($statement->errorCode(), array('00000', 'HY000'))) {
			$errorInfo = $statement->errorInfo();
			trigger_error($errorInfo[0] . ": " . $errorInfo[2], E_USER_WARNING);
			return false;
		}
	} else {
		$result = $statement;
	}
	return $result;
}


function we7_build_db($server, $db_username, $db_password, $db_name, $db_prefix) {
	if (empty($server) || empty($db_username) || empty($db_password) || empty($db_name)) {
		return false;
	}
	$pieces = explode(':', $server);
	$db = array(
		'server' => $pieces[0] == '127.0.0.1' ? 'localhost' : $pieces[0],
		'port' => !empty($pieces[1]) ? $pieces[1] : '3306',
		'username' => $db_username,
		'password' => $db_password,
		'prefix' => $db_prefix,
		'name' => $db_name,
	);
	$error = '';
	try {
		$link = new PDO("mysql:host={$db['server']};port={$db['port']}", $db['username'], $db['password']); 	
		we7_pdo($link, 'exec', "SET character_set_connection=utf8, character_set_results=utf8, character_set_client=binary");
		we7_pdo($link, 'exec', "SET sql_mode=''");
		$databases = we7_pdo($link, 'query', "SHOW DATABASES LIKE '{$db['name']}';");
		$db_version = substr($link->getAttribute(PDO::ATTR_SERVER_VERSION), 0, 3);
		if (empty($databases)) {
			if (version_compare($db_version, '5.6') >= 0) {
				we7_pdo($link, 'query', "CREATE DATABASE IF NOT EXISTS `{$db['name']}` DEFAULT CHARACTER SET utf8mb4;");
			} else {
				line('mysql最低版本要求为5.6');
			}
		}
		if ($db_version == '5.6') {
			$innodb_large_prefix = we7_pdo($link, 'exec', "SET GLOBAL innodb_large_prefix=1");
			$innodb_file_format = we7_pdo($link, 'exec', "SET GLOBAL innodb_file_format=BARRACUDA");
			if (false === $innodb_file_format || false === $innodb_large_prefix) {
				line('mysql5.6版本下数据库用户名及密码需使用root账号');
			}
		}
		$databases_if_exists = we7_pdo($link, 'query', "SHOW DATABASES LIKE '{$db['name']}';");
		if (empty($databases_if_exists)) {
			$error = "数据库不存在且创建数据库失败。";
		}
		we7_pdo($link, 'exec', "USE `{$db_name}`;");
		$tables = we7_pdo($link, 'query', "SHOW TABLES LIKE '{$db_prefix}%';");
		if (!empty($tables)) {
			line('您的数据库不为空，请重新建立数据库或是清空该数据库或更改表前缀！');
		}
	} catch (PDOException $e) {
		trigger_error($e->getCode() . ':' . $e->getMessage());
		$error = $e->getMessage();
		if (strpos($error, 'Access denied for user') !== false) {
			$error = '您的数据库访问用户名或是密码错误。';
		} elseif (strpos($error, 'No such file or directory') !== false || strpos($error, 'Name or service not known') !== false) {
			$error = '无法连接数据库，请检查数据库是否正常。详情：' . $error;
		} else {
			$error = iconv('gbk', 'utf8', $error);
		}
	}
	if (!empty($error)) {
		line($error);
	}
	return true;
}


function we7_db($db = [], $cookiepre = '', $authkey = '') {
	$link = new PDO("mysql:dbname={$db['name']};host={$db['server']};port={$db['port']}", $db['username'], $db['password']);
	we7_pdo($link, 'exec', "SET character_set_connection=utf8, character_set_results=utf8, character_set_client=binary");
	we7_pdo($link, 'exec', "SET sql_mode=''");
	$dat = require IA_INIT_ROOT . '/data/db-1.x.php';
	$support_innodb = false;
	$engines = $link->query("SHOW ENGINES;");
	$all_engines = $engines->fetchAll();
	foreach ($all_engines as $engine) {
		if (strtolower($engine['Engine']) == 'innodb' && in_array(strtolower($engine['Support']), array('default', 'yes'))) {
			$support_innodb = true;
		}
	}
	foreach ($dat['schemas'] as $schema) {
		$sql = local_create_sql($schema, $support_innodb);
		local_run($sql, $link, $db);
	}
	foreach ($dat['datas'] as $data) {
		local_run($data, $link, $db);
	}
	
	$user = array('username' => 'admin', 'password' => local_salt(12));
	$salt = local_salt(8);
	$password = sha1("{$user['password']}-{$salt}-{$authkey}");
	$sql = "INSERT INTO `{$db['prefix']}users` (`username`, `password`, `salt`, `joindate`, `groupid`, `status`, `founder_groupid`, `is_bind`) VALUES('{$user['username']}', '{$password}', '{$salt}', '" . time() . "', 1, 2, 1, 0)";
	$result = we7_pdo($link, 'exec', $sql);
	if (!$result) {
		line('初始用户创建失败，请联系官方处理！');
	}
	$cookie = array('lastvisit' => '', 'lastip' => '');
	$cookie['uid'] = $link->lastInsertId();
	$cookie['hash'] = md5($password . $salt);

	$session = install_authcode(json_encode($cookie), 'encode', $authkey);
	setcookie("{$cookiepre}__session", $session, 0, '/', '', 1, true);

	return true;
}


function local_create_sql($schema, $local_create_sql) {
	$pieces = explode('_', $schema['charset']);
	$charset = $pieces[0];
	$engine = $local_create_sql ? $schema['engine'] : 'InnoDB';
	$sql = "CREATE TABLE IF NOT EXISTS `{$schema['tablename']}` (\n";
	foreach ($schema['fields'] as $value) {
		if (!empty($value['length'])) {
			$length = "({$value['length']})";
		} else {
			$length = '';
		}

		$signed = empty($value['signed']) ? ' unsigned' : '';
		if (empty($value['null'])) {
			$null = ' NOT NULL';
		} else {
			$null = '';
		}
		if (isset($value['default'])) {
			$default = " DEFAULT '" . $value['default'] . "'";
		} else {
			$default = '';
		}
		if ($value['increment']) {
			$increment = ' AUTO_INCREMENT';
		} else {
			$increment = '';
		}

		$sql .= "`{$value['name']}` {$value['type']}{$length}{$signed}{$null}{$default}{$increment},\n";
	}
	foreach ($schema['indexes'] as $value) {
		$fields = implode('`,`', $value['fields']);
		if ($value['type'] == 'index') {
			$sql .= "KEY `{$value['name']}` (`{$fields}`),\n";
		}
		if ($value['type'] == 'unique') {
			$sql .= "UNIQUE KEY `{$value['name']}` (`{$fields}`),\n";
		}
		if ($value['type'] == 'primary') {
			$sql .= "PRIMARY KEY (`{$fields}`),\n";
		}
	}
	$sql = rtrim($sql);
	$sql = rtrim($sql, ',');

	$sql .= "\n) ENGINE=$engine DEFAULT CHARSET=$charset ROW_FORMAT=DYNAMIC;\n\n";
	return $sql;
}


function local_run($sql, $link, $db) {
	if (!isset($sql) || empty($sql)) {
		return;
	}

	$sql = str_replace("\r", "\n", str_replace(' ims_', ' ' . $db['prefix'], $sql));
	$sql = str_replace("\r", "\n", str_replace(' `ims_', ' `' . $db['prefix'], $sql));
	$ret = array();
	$num = 0;
	foreach (explode(";\n", trim($sql)) as $query) {
		$ret[$num] = '';
		$queries = explode("\n", trim($query));
		foreach ($queries as $query) {
			$ret[$num] .= (isset($query[0]) && $query[0] == '#') || (isset($query[1]) && isset($query[1]) && $query[0] . $query[1] == '--') ? '' : $query;
		}
		$num++;
	}
	unset($sql);
	foreach ($ret as $query) {
		$query = trim($query);
		if ($query) {
			$link->exec($query);
			if ($link->errorCode() != '00000') {
				$errorInfo = $link->errorInfo();
				trigger_error($errorInfo[0] . ": " . $errorInfo[2], E_USER_WARNING);
				exit($query);
			}
		}
	}
}


function local_salt($length = 8) {
	$strs = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklnmopqrstuvwxyz0123456789';
	$result = substr(str_shuffle($strs), mt_rand(0, strlen($strs) - ($length + 1)), $length);
	return $result;
}


function install_authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
	$ckey_length = 4;
	$key = md5($key);
	$keya = md5(substr($key, 0, 16));
	$keyb = md5(substr($key, 16, 16));
	$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';

	$cryptkey = $keya . md5($keya . $keyc);
	$key_length = strlen($cryptkey);

	$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
	$string_length = strlen($string);

	$result = '';
	$box = range(0, 255);

	$rndkey = array();
	for ($i = 0; $i <= 255; $i++) {
		$rndkey[$i] = ord($cryptkey[$i % $key_length]);
	}

	for ($j = $i = 0; $i < 256; $i++) {
		$j = ($j + $box[$i] + $rndkey[$i]) % 256;
		$tmp = $box[$i];
		$box[$i] = $box[$j];
		$box[$j] = $tmp;
	}

	for ($a = $j = $i = 0; $i < $string_length; $i++) {
		$a = ($a + 1) % 256;
		$j = ($j + $box[$a]) % 256;
		$tmp = $box[$a];
		$box[$a] = $box[$j];
		$box[$j] = $tmp;
		$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
	}

	if ($operation == 'DECODE') {
		if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
			return substr($result, 26);
		} else {
			return '';
		}
	} else {
		return $keyc . str_replace('=', '', base64_encode($result));
	}
}